package p.ithorns.integration.hazelcast.config;

import com.hazelcast.config.*;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.boot.autoconfigure.hazelcast.HazelcastProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import p.ithorns.integration.db.mapper.UserMapper;
import p.ithorns.integration.hazelcast.map.MapStoreImpl;
import p.ithorns.integration.hazelcast.serialization.MybatisPlusBaseMapperSerializer;

import java.io.IOException;
import java.net.URL;

/**
 * HazelcastConfig
 *
 * @author Ht.L
 * @date 2023-10-01 19:58
 * @since 1.0.0
 */
@Slf4j
@Configuration
// @ImportResource(locations = "classpath:hazelcast.xml")
public class HazelcastConfig {

    @Bean
    public HazelcastInstance hazelcastInstance(Config config) {
        HazelcastInstance instance = StringUtils.hasText(config.getInstanceName())
                ? Hazelcast.getOrCreateHazelcastInstance(config)
                : Hazelcast.newHazelcastInstance(config);

        log.info("========> 实例化HZ: {}, Cluster: {}", instance, config.getClusterName());
        return instance;
    }

    /**
     * 这里的Config和HazelcastInstance实例化后获取到的Config不是一个，
     * 是其子类DynamicConfigurationAwareConfig；
     * 尤其在后面加入各种Config的时候，会出现问题
     * 所以尽量先初始化Config
     */
    @Bean
    public Config config(HazelcastProperties properties,
                         ResourceLoader resourceLoader,
                         CompactSerializationConfig csConfig,
                         MapConfig mapConfig) throws IOException {
        Resource configLocation = properties.resolveConfigLocation();

        Config config = configLocation != null ? this.loadConfig(configLocation) : Config.load();
        config.setClassLoader(resourceLoader.getClassLoader());

        // 序列化
        config.getSerializationConfig()
                .setCompactSerializationConfig(csConfig);

        // MapStore
        config.addMapConfig(mapConfig);

        return config;
    }

    @Bean
    public CompactSerializationConfig csConfig(SqlSessionFactory sqlSessionFactory) {
        return new CompactSerializationConfig()
                .addSerializer(new MybatisPlusBaseMapperSerializer(sqlSessionFactory));
    }

    @Bean
    public MapConfig mapConfig(UserMapper userMapper) {
        MapStoreImpl mapStore = new MapStoreImpl();
        mapStore.setUserMapper(userMapper);

        MapStoreConfig mapStoreConfig = new MapStoreConfig();
        mapStoreConfig.setClassName("com.hazelcast.mapstore.GenericMapStore");
//        mapStoreConfig.setProperty("external-data-store-ref", "my-mysql-database");
        mapStoreConfig.setImplementation(mapStore);

        MapConfig mapConfig = new MapConfig("local");
        mapConfig.setMapStoreConfig(mapStoreConfig);

        return mapConfig;
    }

    private Config loadConfig(Resource configLocation) throws IOException {
        URL configUrl = configLocation.getURL();
        Config config = loadConfig(configUrl);
        if (ResourceUtils.isFileURL(configUrl)) {
            config.setConfigurationFile(configLocation.getFile());
        } else {
            config.setConfigurationUrl(configUrl);
        }

        return config;
    }

    private static Config loadConfig(URL configUrl) throws IOException {
        String configFileName = configUrl.getPath();
        return configFileName.endsWith(".yaml") ? (new YamlConfigBuilder(configUrl)).build() : (new XmlConfigBuilder(configUrl)).build();
    }

    //@Bean
    public Config config() {
        ManagementCenterConfig centerConfig = new ManagementCenterConfig();
        centerConfig.addTrustedInterface("http://127.0.0.1:8080");

        Config config = new Config();
        config.getNetworkConfig().setPort(5500);

        config.setInstanceName("hz-inst")
                .setClusterName("test")
//                .setManagementCenterConfig(centerConfig)
                .addMapConfig(
                        new MapConfig()
                                .setName("instruments")
                                .setTimeToLiveSeconds(300)
                )
        ;

        return config;
    }

//    @Bean("hazelcastClient")
//    public HazelcastInstance hazelcastInstance(ClientConfig config) {
//        HazelcastInstance hazelcastInstance = HazelcastClient.newHazelcastClient(config);
//        return hazelcastInstance;
//    }

}